package com.huawei.java.pojo;

import java.util.List;

/**
 * 服务器实体类
 * @author 金昊霖
 */
public final class Server {
    /**
     * 服务器虚拟id（并非题目要求的真实id）
     */
    private final int id;
    /**
     * 节点A
     */
    private final Node nodeA;
    /**
     * 节点B
     */
    private final Node nodeB;

    /**
     * 该服务器节点A是否已经装满了
     */
    private boolean AisFull;

    /**
     * 该服务器节点B是否已经装满了
     */
    private boolean BisFull;
    /**
     * 平衡因子，如果超过平衡因子，则不让添加虚拟机
     */
    public static double balanceFactor=3;

    /**
     * 平衡边界
     */
    public static int balanceBorder=30;
    /**
     * 此属性为计数器
     */
    static int count=0;



    /**
     * 加入一台虚拟机，如果双节点加入成功，返回0；如果单节点部署a节点部署成功，返回1；如果部署b节点成功，返回2；不成功返回null
     * 如果加入成功会自动修改该虚拟机对象里的部署服务器id和节点
     * 此方法不进行平衡检测，但是每次成功插入会对自身状态进行更新
     * @param virtualMachine 虚拟机对象
     * @return 如果双节点加入成功，返回0；如果单节点部署a节点部署成功，返回1；如果部署b节点成功，返回2；不成功返回null
     */
    public Integer addVirtualMachine(VirtualMachine virtualMachine,List<Integer> virtualMachineIds){
        VirtualMachineType type=virtualMachine.getVirtualMachineType();
        //如果是双结点部署
        if (type.getType()==1){
            int core=type.getCores()>>1;
            int memory=type.getMemory()>>1;
            int coreA=nodeA.getSurplusCores()-core;
            int memoryA=nodeA.getSurplusMemory()-memory;
            int coreB=nodeB.getSurplusCores()-core;
            int memoryB=nodeB.getSurplusMemory()-memory;

            //如果符合要求则放入服务器，并更改相应参数
            if (coreA>=0&&coreB>=0&&memoryA>=0&&memoryB>=0){
                //对节点资源进行修改
                nodeA.setSurplusCores(coreA);
                nodeA.setSurplusMemory(memoryA);
                nodeB.setSurplusCores(coreB);
                nodeB.setSurplusMemory(memoryB);
                //设置该虚拟机的serverId和node
                virtualMachine.setServerId(id);
                virtualMachine.setNode(0);
                virtualMachineIds.add(virtualMachine.getId());
                return 0;
            }
        }else {
            //如果nodeA的剩余资源和大于nodeB
            if (nodeA.getSurplusCores()+ nodeA.getSurplusMemory()>nodeB.getSurplusCores()+ nodeB.getSurplusMemory()){
                //如果节点A符合就放入
                if (addNodeA(virtualMachine,virtualMachineIds)){
                    return 1;
                }
                //如果节点B符合就放入
                if (addNodeB(virtualMachine,virtualMachineIds)){
                    return 2;
                }
            }else {
                //如果节点B符合就放入
                if (addNodeB(virtualMachine,virtualMachineIds)){
                    return 2;
                }
                //如果节点A符合就放入
                if (addNodeA(virtualMachine,virtualMachineIds)){
                    return 1;
                }
            }
        }
        return null;
    }


    /**
     * 平衡加入虚拟机，此操作有进行平衡检测
     * @param virtualMachine 虚拟机
     * @return 部署节点，如果null则说明此次部署未成功
     */
    public Integer balancedAddVirtualMachine(VirtualMachine virtualMachine,List<Integer> virtualMachineIds){
        //如果相应节点已经满了，直接返回null即可
        if (virtualMachine.getNode()==0){
            if (AisFull||BisFull){
                return null;
            }
        }else if (virtualMachine.getNode()==1){
            if (AisFull){
                return null;
            }
        }else {
            if (BisFull){
                return null;
            }
        }
        VirtualMachineType type=virtualMachine.getVirtualMachineType();
        int core=type.getCores();
        int memory=type.getMemory();
        //如果是双结点部署
        if (type.getType()==1){
            core=core>>1;
            memory=memory>>1;
            int coreA=nodeA.getSurplusCores()-core;
            int memoryA=nodeA.getSurplusMemory()-memory;
            int coreB=nodeB.getSurplusCores()-core;
            int memoryB=nodeB.getSurplusMemory()-memory;
            if (balancedCheck(coreA,memoryA,1)&&balancedCheck(coreB,memoryB,2)){
                //对节点资源进行修改
                nodeA.setSurplusCores(coreA);
                nodeA.setSurplusMemory(memoryA);
                nodeB.setSurplusCores(coreB);
                nodeB.setSurplusMemory(memoryB);
                //设置该虚拟机的serverId和node
                virtualMachine.setServerId(id);
                virtualMachine.setNode(0);
                virtualMachineIds.add(virtualMachine.getId());
                return 0;
            }
        }else {
            //如果nodeA的剩余资源和大于nodeB
            if (nodeA.getSurplusCores()+ nodeA.getSurplusMemory()>= nodeB.getSurplusCores()+nodeB.getSurplusMemory()){
                int coreA=nodeA.getSurplusCores()-core;
                int memoryA=nodeA.getSurplusMemory()-memory;

                if (balancedCheck(coreA,memoryA,1)){
                    nodeA.setSurplusCores(coreA);
                    nodeA.setSurplusMemory(memoryA);
                    virtualMachine.setServerId(id);
                    virtualMachine.setNode(1);
                    virtualMachineIds.add(virtualMachine.getId());
                    return 1;
                }
                int coreB=nodeB.getSurplusCores()-core;
                int memoryB=nodeB.getSurplusMemory()-memory;
                if (balancedCheck(coreB,memoryB,2)){
                    nodeB.setSurplusCores(coreB);
                    nodeB.setSurplusMemory(memoryB);
                    virtualMachine.setServerId(id);
                    virtualMachine.setNode(2);
                    virtualMachineIds.add(virtualMachine.getId());
                    return 2;
                }
            }else {
                int coreB=nodeB.getSurplusCores()-core;
                int memoryB=nodeB.getSurplusMemory()-memory;
                if (balancedCheck(coreB,memoryB,2)){
                    nodeB.setSurplusCores(coreB);
                    nodeB.setSurplusMemory(memoryB);
                    virtualMachine.setServerId(id);
                    virtualMachine.setNode(2);
                    virtualMachineIds.add(virtualMachine.getId());
                    return 2;
                }
                int coreA=nodeA.getSurplusCores()-core;
                int memoryA=nodeA.getSurplusMemory()-memory;
                if (balancedCheck(coreA,memoryA,1)){
                    nodeA.setSurplusCores(coreA);
                    nodeA.setSurplusMemory(memoryA);
                    virtualMachine.setServerId(id);
                    virtualMachine.setNode(1);
                    virtualMachineIds.add(virtualMachine.getId());
                    return 1;
                }
            }
        }
        return null;
    }
    /**
     * 根据虚拟机删除一台虚拟机
     * 判断该服务器上是否有该虚拟机，需要在外部判断
     * @param virtualMachine 要删除的虚拟机
     */
    public void deleteVirtualMachine(VirtualMachine virtualMachine,Integer node,List<Integer> virtualMachineIds){
        VirtualMachineType vt = virtualMachine.getVirtualMachineType();
        int cores= vt.getCores();
        int memory= vt.getMemory();
        //更改节点内的剩余资源
        if (node==0){
            nodeA.setSurplusCores(nodeA.getSurplusCores()+(cores>>1));
            nodeA.setSurplusMemory(nodeA.getSurplusMemory()+(memory>>1));
            nodeB.setSurplusCores(nodeB.getSurplusCores()+(cores>>1));
            nodeB.setSurplusMemory(nodeB.getSurplusMemory()+(memory>>1));
            AisFull=false;
            BisFull=false;
        }else if (node==1){
            //如果该虚拟机部署在A节点
            nodeA.setSurplusCores(nodeA.getSurplusCores()+cores);
            nodeA.setSurplusMemory(nodeA.getSurplusMemory()+memory);
            AisFull=false;
        }else if(node==2){
            //如果该虚拟机部署在B节点
            nodeB.setSurplusCores(nodeB.getSurplusCores()+cores);
            nodeB.setSurplusMemory(nodeB.getSurplusMemory()+memory);
            BisFull=false;
        }
        virtualMachineIds.remove(virtualMachine.getId());
    }
    /**
     * 根据虚拟机删除一台虚拟机,此方法是为了在外面遍历时还能删除对应id，所以此方法的删除操作不会对自身的虚拟机id集合删除，需要外部执行
     * @param virtualMachine 要删除的虚拟机
     */
    public void simpleDeleteVirtualMachine(VirtualMachine virtualMachine,Integer node){
        VirtualMachineType vt = virtualMachine.getVirtualMachineType();
        int cores= vt.getCores();
        int memory= vt.getMemory();
        //更改节点内的剩余资源
        if (node==0){
            nodeA.setSurplusCores(nodeA.getSurplusCores()+(cores>>1));
            nodeA.setSurplusMemory(nodeA.getSurplusMemory()+(memory>>1));
            nodeB.setSurplusCores(nodeB.getSurplusCores()+(cores>>1));
            nodeB.setSurplusMemory(nodeB.getSurplusMemory()+(memory>>1));
            AisFull=false;
            BisFull=false;
        }else if (node==1){
            //如果该虚拟机部署在A节点
            nodeA.setSurplusCores(nodeA.getSurplusCores()+cores);
            nodeA.setSurplusMemory(nodeA.getSurplusMemory()+memory);
            AisFull=false;
        }else if(node==2){
            //如果该虚拟机部署在B节点
            nodeB.setSurplusCores(nodeB.getSurplusCores()+cores);
            nodeB.setSurplusMemory(nodeB.getSurplusMemory()+memory);
            BisFull=false;
        }
    }



    /**
     * 根据服务器类型创建服务器
     * @param serverType 服务器类型对象
     */
    public Server(ServerType serverType) {
        this.id = count++;
        this.nodeA = new Node(serverType.getCores()>>1, serverType.getMemory()>>1);
        this.nodeB = new Node(serverType.getCores()>>1, serverType.getMemory()>>1);
    }

    /**
     * 把虚拟机加入结点A
     * @param v 虚拟机
     * @return 成功返回1，失败返回null
     */
    private boolean addNodeA(VirtualMachine v,List<Integer> virtualMachineIds){
        VirtualMachineType type=v.getVirtualMachineType();
        int coreA=nodeA.getSurplusCores()- type.getCores();
        int memoryA=nodeA.getSurplusMemory()-type.getMemory();
        if (coreA>=0&&memoryA>=0){
            nodeA.setSurplusCores(coreA);
            nodeA.setSurplusMemory(memoryA);
            v.setServerId(id);
            v.setNode(1);
            virtualMachineIds.add(v.getId());
            return true;
        }
        return false;
    }
    /**
     * 把虚拟机加入结点B
     * @param v 虚拟机
     * @return 成功返回1，失败返回null
     */
    private boolean addNodeB(VirtualMachine v,List<Integer> virtualMachineIds){
        VirtualMachineType type=v.getVirtualMachineType();
        int coreB =nodeB.getSurplusCores()- type.getCores();
        int memoryB =nodeB.getSurplusMemory()-type.getMemory();
        if (coreB >=0&& memoryB >=0){
            nodeB.setSurplusCores(coreB);
            nodeB.setSurplusMemory(memoryB);
            v.setServerId(id);
            v.setNode(2);
            virtualMachineIds.add(v.getId());
            return true;
        }
        return false;
    }

    /**
     * 平衡检查同时检查是否能插入,true表示通过，false表示不通过
     * @param c 规划后剩下的虚拟机内核(一般为A或B)
     * @param m 规划后剩下的虚拟机内存
     * @return true表示通过，false表示不通过
     */
    private  boolean balancedCheck(Integer c,Integer m,int node){
        if (c<0||m<0){
            return false;
        }
        if (c+m<balanceBorder){
            if (node==1){
                AisFull =true;
            }else {
                BisFull=true;
            }
            return true;
        }else if (c==0||m==0){
            return false;
        }
        double a=c*1.0/m;
        return !(a < balanceFactor * 0.33) && !(a > balanceFactor * 3);
    }

    /**
     * 调用时更新状态(给外部调用)，同时返回是否平衡,0表示双节点，1表示节点A，2表示节点B
     * @return 是否平衡
     */
    public boolean simpleCheck(final int node){
        if (node==0){
            if (nodeA.getSurplusCores()+nodeA.getSurplusMemory()<balanceBorder
                    &&nodeA.getSurplusCores()+nodeA.getSurplusMemory()<balanceBorder){
                AisFull=true;
                BisFull=true;
                return true;
            }
            double a=1.0*nodeA.getSurplusCores()/nodeA.getSurplusMemory();
            double b=1.0*nodeB.getSurplusCores()/nodeB.getSurplusMemory();
            return !(a <  balanceFactor*0.33) && !(a > balanceFactor*3)&&!(b < balanceFactor*0.33) && !(b > balanceFactor*3);
        }
        if (node==1){
            if (nodeA.getSurplusCores()+nodeA.getSurplusMemory()<balanceBorder){
                AisFull=true;
                return true;
            }
            double a=1.0*nodeA.getSurplusCores()/nodeA.getSurplusMemory();
            return !(a <  balanceFactor*0.33) && !(a > balanceFactor*3);
        }else {
            if (nodeB.getSurplusCores()+nodeB.getSurplusMemory()<balanceBorder){
                BisFull=true;
                return true;
            }
            double b=1.0*nodeB.getSurplusCores()/nodeB.getSurplusMemory();
            return !(b < balanceFactor*0.33) && !(b > balanceFactor*3);
        }
    }

    public static int getCount() {
        return count;
    }

    public int getId() {
        return id;
    }

    /**
     * 当前剩余的总资源
     * @return 当前剩余的总资源
     */
    public int getResource(){
        return nodeA.getSurplusCores()+nodeA.getSurplusMemory()+nodeB.getSurplusCores()+nodeB.getSurplusMemory();
    }


    /**
     * 修改计数器
     * @param count 计数器
     */
    public static void setCount(int count) {
        Server.count = count;
    }

    public boolean isAisFull() {
        return AisFull;
    }

    public boolean isBisFull() {
        return BisFull;
    }
}
